 package com.gmrz.uaf.policy.json;

 import com.gmrz.service.challengestore.ChallengeStoreException;
import com.gmrz.service.challengestore.ChallengeStoreService;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.common.PoliceJson;
import com.gmrz.uaf.common.UAFRuntimeException;
import com.gmrz.uaf.common.service.challengestore.UAFChallengeStoreServiceProvider;
import com.gmrz.uaf.db.DAOException;
import com.gmrz.uaf.db.UAFDAOFactory;
import com.gmrz.uaf.db.UAFDBConnectionMgr;
import com.gmrz.uaf.db.dao.UasConfigDAO;
import com.gmrz.uaf.policy.PolicyManager;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.MatchCriteria;
import com.gmrz.uaf.protocol.v1.schema.Policy;
import com.gmrz.uaf.protocol.v1.validaton.PolicyValidationException;
import com.gmrz.uaf.protocol.v1.validaton.PolicyValidator;
import com.gmrz.util.Strings;
import com.gmrz.util.db.DBUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

import static com.gmrz.uaf.common.Constants.POLICY_NAME_PREFIX;

 public class JSONPolicyManager
   implements PolicyManager
 {
   private static final Logger LOG = LogManager.getLogger(JSONPolicyManager.class);


	private JSONPolicyStore policyStore = null;
	private ChallengeStoreService muafChallengeStoreService=null;
 
   @Inject
   private void setPolicyFile() {

	   // 从缓存中读取json串
	   String policyString =null;
	   HashMap<String,String> policyStrList=new HashMap<String,String>();
	   UAFChallengeStoreServiceProvider mUafChallenge =
			   GuiceUtil.getProcessorInjector().getInstance(UAFChallengeStoreServiceProvider.class);
	   try {
		   muafChallengeStoreService=mUafChallenge.get();
		   policyString=muafChallengeStoreService.getvalue("uaf.policy.json");
		   // LOG.info("Loading policies from cache[{}]", policyString);
		   if(!Strings.isNullOrEmpty(policyString)){
			   policyStrList.put("policy.json", policyString);
			   if (policyStrList != null)
				   policyString = policyStrList.get("policy.json");
		   }
	   } catch (ChallengeStoreException e) {
		   LOG.error("Failed to read the  policy.json data from the cache. ", e);
		   //throw new UAFRuntimeException("Failed to load policy", e);
	   } catch (Exception e){
		   LOG.error(e);
		   //throw new UAFRuntimeException("Failed to load policy", e);
	   }
	   //从数据库中获取信息列表
       Connection conn = null;
	   if(policyString==null) {
		   HashMap<String, PoliceJson> PoliceJson = new HashMap<String, PoliceJson>();
		   try {
			   conn = UAFDBConnectionMgr.getConnection(true);
//			   UasConfigDAO policyDao = GuiceUtil.getProcessorInjector().getInstance(DAOFactory.class)
//					   .createUasConfigDAO(conn);
			   UasConfigDAO policyDao = UAFDAOFactory.createUasConfigDAO(conn);
			   PoliceJson = policyDao.LoadPolicyJson();
			   Gson gson = new Gson();
			   policyString = gson.toJson(PoliceJson);
			   LOG.info("policy[{}] value",policyString);
			   if (!Strings.isNullOrEmpty(policyString)) {
				   muafChallengeStoreService.putString("uaf.policy.json", policyString);
			   }
		   } catch (SQLException sqle) {
			   LOG.error("Failed to access the policy data from db ", sqle);
			   throw new UAFRuntimeException("Failed to load policy", sqle);
		   } catch (ChallengeStoreException e) {
			   LOG.error("Failed to write the policy.json data into cache.", e);
			   throw new UAFRuntimeException("Failed to load policy", e);
		   } catch (DAOException e){
			   LOG.error(e);
			   throw new UAFRuntimeException("Failed to load policy", e);
		   } catch (Exception e){
			   LOG.error(e);
			   throw new UAFRuntimeException("Failed to load policy", e);
		   }finally {
			   DBUtil.close(conn);
		   }
	   }
	   try {
		   GsonBuilder builder = UAFSchemaBuilder.getBuilder();
		   builder.registerTypeAdapter(JSONPolicyStore.class, new JSONAdapter());
		   Gson gson = builder.create();
		   //LOG.info("policyString:" + policyString);
		   JSONPolicyStore readPolicyStore = gson.fromJson(policyString, JSONPolicyStore.class);
		   //LOG.info("JSONPolicyStore:" + gson.toJson(readPolicyStore) );
		   this.policyStore = readPolicyStore;
	   } catch (Exception e) {
		   LOG.error("Failed to deserialize policy JSON content", e);
		   throw new UAFRuntimeException("Failed to deserialize policy JSON content", e);
	   }
	   LOG.info("Successfully loaded the policies.");
   }

     public void validatePolicies() throws PolicyValidationException {
     if (this.policyStore != null)
       for (Policy p : this.policyStore.getAllPolicies().values())
         try {
           LOG.info("Validate the following policy[{}] ", p.getPolicyName());
           PolicyValidator policyValidator = GuiceUtil.getProcessorInjector().getInstance(PolicyValidator.class);
           policyValidator.validate(p);
         } catch (Exception ex) {
           LOG.error("Policy validation failed for policy[{}]", p.getPolicyName(), ex);
           throw new PolicyValidationException(UAFErrorCode.PROTOCOL_POLICY_VALIDATION_FAILED);
         }
   }



   public Policy getNamedPolicy(String authType,String appID)
   {
       String policyName = POLICY_NAME_PREFIX+appID+"_"+authType;
	   return this.policyStore.get(policyName);
   }

	 @Override
	 public Policy getNamedPolicy(String authType, String appID, String transType) {

		 if(null != transType && !"".equals(transType)){
			 String policyName = POLICY_NAME_PREFIX+appID+"_"+authType+"_"+transType;
			 // 缓存中进行读取，系统启动时会先从redis中读取策略然后放到 JSONPolicyStore的map集合属性中
			 return this.policyStore.get(policyName);
		 }else {
			 Policy returnPolicy = null;
			 String policyName = POLICY_NAME_PREFIX+appID+"_"+authType;
			 Map<String,Policy> policyMap = this.policyStore.getAllPolicies();
			 Iterator<Map.Entry<String,Policy>> it =  policyMap.entrySet().iterator();
			 while (it.hasNext()){
				 Map.Entry<String,Policy> en = it.next();
				 String key = en.getKey();
				 if(key.startsWith(policyName)){
					 if(null == returnPolicy){
						 returnPolicy = en.getValue();
					 }else {
						 List<List<MatchCriteria>> list = en.getValue().getAccepted();
						 if(null != list && !list.isEmpty()){
							 for(List<MatchCriteria> matchCriteriaList : list){
								 String aaid = matchCriteriaList.get(0).getAAID().get(0).toString();
								 if(Strings.isNotBlank(aaid)) {
									 boolean flag = false;
									 List<List<MatchCriteria>> returnPolicyAccepted = returnPolicy.getAccepted();
									 if (null == returnPolicyAccepted) {
										 returnPolicyAccepted = new ArrayList<List<MatchCriteria>>();
									 }
									 for (List<MatchCriteria> returnPolicyAcceptedMatchCriteriaList : returnPolicyAccepted) {
										 String returnAaid = returnPolicyAcceptedMatchCriteriaList.get(0).getAAID().get(0).toString();
										 if (aaid.equals(returnAaid)) {
											 flag = true;
											 break;
										 }
									 }
									 if (!flag) {
										 returnPolicyAccepted.add(matchCriteriaList);
									 }
								 }
							 }
						 }
					 }

				 }
			 }
			 return returnPolicy;
		 }
	 }

 }
